package org.origin.centre.security.authentication.details;

import jakarta.servlet.http.HttpServletRequest;
import org.origin.centre.support.utils.BasicUtil;
import org.origin.centre.support.utils.ServletUtil;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.www.BasicAuthenticationConverter;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 自定义多个渠道端登录认证
 *
 * @author ferret
 * @version 2024-05-08
 */
public class DefaultMultipleUserDetailsService implements UserDetailsService, ApplicationContextAware {
    private final BasicAuthenticationConverter basicConvert = new BasicAuthenticationConverter();
    protected Map<String, XUserDetailsService> userDetailsServiceMap;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        try {
            HttpServletRequest request = ServletUtil.getRequest();
            String clientId = this.basicConvert.convert(request).getName();
            XUserDetailsService userDetailsService = this.userDetailsServiceMap.get(clientId);
            if (userDetailsService == null) {
                throw new IllegalAccessException("clientId is not found");
            }
            UserDetails loadedUser = userDetailsService.getByAccount(clientId, username);
            if (loadedUser == null) {
                throw new InternalAuthenticationServiceException(
                        "UserDetailsService returned null, which is an interface contract violation");
            }
            return loadedUser;
        } catch (UsernameNotFoundException | InternalAuthenticationServiceException ex) {
            throw ex;
        } catch (Exception ex) {
            throw new InternalAuthenticationServiceException(ex.getMessage(), ex);
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String, XUserDetailsService> userDetailsServiceMapByClientId = new HashMap<>();
        Map<String, XUserDetailsService> userDetailsServiceMapByName = applicationContext.getBeansOfType(XUserDetailsService.class);
        for (XUserDetailsService userDetailsService : userDetailsServiceMapByName.values()) {
            List<String> clientIds = userDetailsService.getClientIds();
            if (clientIds != null && clientIds.size() > 0) {
                for (String clientId : clientIds) {
                    if (BasicUtil.isNotBlank(clientId)) {
                        userDetailsServiceMapByClientId.put(clientId, userDetailsService);
                    }
                }
            }
        }
        this.userDetailsServiceMap = userDetailsServiceMapByClientId;
    }
}
